package lsem.eclipse.vdf.ui.natures;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import lsem.eclipse.vdf.ui.Activator;
import lsem.eclipse.vdf.ui.handler.SaveAliasAndStartDBHandler;
import lsem.eclipse.vdf.ui.misc.DbGraphCreator;
import lsem.eclipse.vdf.ui.misc.FileUtilities;
import lsem.eclipse.vdf.ui.navigator.VDFCommonNavigatorView;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.IHandlerService;
import org.osgi.framework.Bundle;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class VDFProjectSupport {

	private static File projectFile;

	/**
	 * For this marvelous project we need to: - create the default Eclipse
	 * project - add the custom project nature - create the folder structure
	 * 
	 * @param projectName
	 * @param location
	 * @param natureId
	 * @return
	 */
	public static IProject createProject(String projectName, URI location) {
		Assert.isNotNull(projectName);
		Assert.isTrue(projectName.trim().length() > 0);
		readProjectFile();

		IProject project = createBaseProject(projectName, location);

		try {
			addNature(project);

			ArrayList<String> pathList = new ArrayList<String>();
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			if (projectFile.exists()) {
				Document doc = db.parse(projectFile);
				Element docEle = doc.getDocumentElement();

				// Print root element of the document
				System.out.println("Root element of the document: "
						+ docEle.getNodeName());

				NodeList nList = docEle.getChildNodes();

				pathList = loopXMLFile(nList, "");
			}

			addToProjectStructure(project, pathList);
			//Copy UBL Schema Files to Project.
			copyFilesToProject("XML-Files" + File.separator
						+ "UBL-2.0-SCHEMA" + File.separator + "xsd", project.getFolder("\\Dataformat\\UBL"));
		} catch (CoreException e) {
			e.printStackTrace();
			project = null;
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		new DbGraphCreator(projectName);

		// execute command
		IWorkbenchWindow window = PlatformUI.getWorkbench()
				.getActiveWorkbenchWindow();
		IViewPart view = window.getActivePage().findView(
				VDFCommonNavigatorView.ID);
		IHandlerService service = (IHandlerService) view.getSite().getService(
				IHandlerService.class);

		Event event = new Event();
		event.text = projectName;
		try {
			service.executeCommand(SaveAliasAndStartDBHandler.ID, event);
		} catch (Exception ex) {
			throw new RuntimeException(SaveAliasAndStartDBHandler.ID);
		}
		return project;

	}

	private static ArrayList<String> loopXMLFile(NodeList nList,
			String parentPathName) {

		ArrayList<String> pathList = new ArrayList<String>();
		for (int i = 0; i < nList.getLength(); i++) {

			Node nodeXML = nList.item(i);

			if (nodeXML.getNodeType() == Node.ELEMENT_NODE) {

				System.out.println("\n =====================");

				Element e = (Element) nodeXML;
				if (!e.hasChildNodes()) {
					if (e.hasAttribute("type")) {
						System.out.print("\n Element name: "
								+ e.getAttribute("name"));
						String pathNameTemp = parentPathName + File.separator
								+ e.getAttribute("addpath")
								+ File.separator
								+ e.getAttribute("name")
								+ e.getAttribute("extension");
						pathList.add(pathNameTemp);
					} else {
						System.out.print("\n Element name: "
								+ e.getAttribute("name"));
						String pathNameTemp = parentPathName + File.separator
								+ e.getAttribute("name");
						pathList.add(pathNameTemp);
					}
				} else if (e.hasAttribute("relationshipType")) {
					if (e.hasAttribute("type")) {
						System.out.print("\n Element name: "
								+ e.getAttribute("name"));
						String pathNameTemp = parentPathName + File.separator
								+ e.getAttribute("name")
								+ e.getAttribute("extension");
						pathList.add(pathNameTemp);
						pathList.addAll(loopXMLFile(e.getChildNodes(),
								pathNameTemp));
					} else {
						System.out.print("\n Element name: "
								+ e.getAttribute("name"));
						String pathNameTemp = parentPathName + File.separator
								+ e.getAttribute("name");
						pathList.add(pathNameTemp);
						pathList.addAll(loopXMLFile(e.getChildNodes(),
								pathNameTemp));
					}

				} else {
					System.out.print("\n Element name: "
							+ e.getAttribute("name"));
					pathList.addAll(loopXMLFile(nodeXML.getChildNodes(),
							parentPathName));
				}

			}
		}

		return pathList;

	}

	/**
	 * Just do the basics: create a basic project.
	 * 
	 * @param location
	 * @param projectName
	 */
	private static IProject createBaseProject(String projectName, URI location) {
		// it is acceptable to use the ResourcesPlugin class
		IProject newProject = ResourcesPlugin.getWorkspace().getRoot()
				.getProject(projectName);

		if (!newProject.exists()) {
			URI projectLocation = location;
			IProjectDescription desc = newProject.getWorkspace()
					.newProjectDescription(newProject.getName());
			if (location != null
					&& ResourcesPlugin.getWorkspace().getRoot()
							.getLocationURI().equals(location)) {
				projectLocation = null;
			}

			desc.setLocationURI(projectLocation);
			try {
				newProject.create(desc, null);
				if (!newProject.isOpen()) {
					newProject.open(null);
				}
			} catch (CoreException e) {
				e.printStackTrace();
			}
		}

		return newProject;
	}

	private static void readProjectFile() {
		Bundle bundle = Activator.getDefault().getBundle();
		Path path = new Path(File.separator
				+ "XML-Files" + File.separator + "projectSetup.xml"); //$NON-NLS-1$
		URL url = FileLocator.find(bundle, path, Collections.EMPTY_MAP);
		URL fileUrl = null;
		try {
			fileUrl = FileLocator.toFileURL(url);
		} catch (IOException e) {
			// Will happen if the file cannot be read for some reason
			e.printStackTrace();
		}
		VDFProjectSupport.projectFile = new File(fileUrl.getPath());
	}

	private static void createFolder(IFolder folder) throws CoreException {
		IContainer parent = folder.getParent();
		if (parent instanceof IFolder) {
			createFolder((IFolder) parent);
		}
		if (!folder.exists()) {
			folder.create(false, true, null);

		}
	}

	private static void createFile(IFile file) throws CoreException {

		createFolder((IFolder) file.getParent());
		String contents = "";
		InputStream source = new ByteArrayInputStream(contents.getBytes());
		file.create(source, false, null);

	}

	/**
	 * Create a folder structure with a parent root, overlay, and a few child
	 * folders.
	 * 
	 * @param newProject
	 * @param paths
	 * @throws CoreException
	 */
	private static void addToProjectStructure(IProject newProject,
			ArrayList<String> paths) throws CoreException {
		for (String path : paths) {
			if (path.contains(".")) {
				IFile file = newProject.getFile(path);
				createFile(file);
			} else {
				IFolder etcFolders = newProject.getFolder(path);
				createFolder(etcFolders);
			}
		}
	}

	private static void copyFilesToProject(String path,
			IFolder folderDestination) {

		Bundle bundle = Activator.getDefault().getBundle();
		Path pathSource = new Path(path);
		URL urlSource = FileLocator.find(bundle, pathSource,
				Collections.EMPTY_MAP);
		URL fileUrlSource = null;
		try {
			fileUrlSource = FileLocator.toFileURL(urlSource);
		} catch (IOException e) {
			// Will happen if the file cannot be read for some reason
			e.printStackTrace();
		}

		IPath destPath = folderDestination.getLocation();
		File source = new File(fileUrlSource.getPath());
		File destination = new File(destPath.toString());
		try {

			FileUtilities.copy(source, destination);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	private static void addNature(IProject project) throws CoreException {
		if (!project.hasNature(ProjectNature.ID)) {
			IProjectDescription description = project.getDescription();
			String[] prevNatures = description.getNatureIds();
			String[] newNatures = new String[prevNatures.length + 1];
			System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length);
			newNatures[prevNatures.length] = ProjectNature.ID;
			description.setNatureIds(newNatures);

			IProgressMonitor monitor = null;
			project.setDescription(description, monitor);
		}
	}

}
